#pragma code_seg("CSAMBA")
#pragma data_seg("DSAMBA")
#pragma bss_seg("BSAMBA")
#pragma const_seg("KSAMBA")
#pragma comment(linker, "/merge:DSAMBA=SAMBA")
#pragma comment(linker, "/merge:CSAMBA=SAMBA")
#pragma comment(linker, "/merge:BSAMBA=SAMBA")
#pragma comment(linker, "/merge:KSAMBA=SAMBA")
/*

    This file is part of the smb++ library

    Copyright (C) 1999  Nicolas Brodu

    nicolas.brodu@free.fr



    This program is free software; you can redistribute it and/or modify

    it under the terms of the GNU General Public License as published by

    the Free Software Foundation; either version 2 of the License, or

    (at your option) any later version.



    This program is distributed in the hope that it will be useful,

    but WITHOUT ANY WARRANTY; without even the implied warranty of

    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

    GNU General Public License for more details.



    You should have received a copy of the GNU General Public License

    along with this program, see the file COPYING; if not, write

    to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,

    MA 02139, USA.

*/



#include "defines.h"

#ifndef USE_SAMBA

#include <string.h>

#include "NameServicePacket.h"



ResourceRecord::ResourceRecord(const char *n, uint16 t, uint16 c, uint16 l, uint8* d, uint16 dl)

{

	nameLength=strlen(n)+1;;

	rrName=new char[nameLength];

	memcpy(rrName,n,nameLength);

	rrType=t; rrClass=c; ttl=l;

	dataLength=dl;

	data=new uint8[dl];

	memcpy(data,d,dl);

}



ResourceRecord::~ResourceRecord()

{

	if (rrName) delete rrName;

	if (data) delete data;

}



uint8* ResourceRecord::build()

{

	uint8* ret=new uint8[nameLength+10+dataLength];

	memcpy(ret,rrName,nameLength);

	// warning from gcc with (uint16*) on left side

	uint16 *p16 = (uint16 *)((uint8*)ret+nameLength);

	*(p16++)=BIGEND16(rrType);

	*p16=BIGEND16(rrClass);	

	uint32 *p32 = (uint32 *)((uint8*)ret+nameLength+4);

	*p32=BIGEND32(ttl);;

	*(p16+3) = BIGEND16(dataLength);

	memcpy(ret+nameLength+10,data,dataLength);

	return ret;

}



uint16 ResourceRecord::getLength()

{

	return nameLength+dataLength+10;

}





NameServicePacket::NameServicePacket()

{

	name_trn_id=0; opcode=0; nmFlags=0; rcode=0;

	qdcount=0; ancount=0; nscount=0; arcount=0;

	questionName=0; questionType=0; questionClass=0;

	questionNameLength=0;

	answerRR=0; authorityRR=0; additionalRR=0;

}
NameServicePacket::~NameServicePacket()
{
  if ( questionName )
    delete questionName;
}

// Get the real length of the packet in byte

uint16 NameServicePacket::getLength()

{

	uint16 ret=12;

	if (questionName) ret+=6+questionNameLength;

	if (answerRR) ret+=answerRR->getLength();

	if (authorityRR) ret+=authorityRR->getLength();

	if (additionalRR) ret+=additionalRR->getLength();

	return ret;

}



uint8* NameServicePacket::packet()

{

	if (modified) update(); // in case subclasses would use it

	uint8 *ret = new uint8[getLength()];

	// Build Header first

	ret[0]=(uint8)(name_trn_id>>8);   // high byte

	ret[1]=(uint8)(name_trn_id&0xFF); // low byte

	ret[2]=((uint32)(opcode&0x1F)<<3) | ((uint32)((nmFlags&0x7F)>>4));

	ret[3]=((uint32)(nmFlags&0x7F)<<4) | ((uint32)(rcode&0x0F));

	ret[4]=(uint8)(qdcount>>8);   // high byte

	ret[5]=(uint8)(qdcount&0xFF); // low byte

	ret[6]=(uint8)(ancount>>8);   // high byte

	ret[7]=(uint8)(ancount&0xFF); // low byte

	ret[8]=(uint8)(nscount>>8);   // high byte

	ret[9]=(uint8)(nscount&0xFF); // low byte

	ret[10]=(uint8)(arcount>>8);   // high byte

	ret[11]=(uint8)(arcount&0xFF); // low byte

	// Complete packet

	if (questionName)

	{

		memcpy(ret+12, questionName, questionNameLength);

		ret[12+questionNameLength]=(uint8)(questionType>>8);   // high byte

		ret[13+questionNameLength]=(uint8)(questionType&0xFF); // low byte

		ret[14+questionNameLength]=(uint8)(questionClass>>8);   // high byte

		ret[15+questionNameLength]=(uint8)(questionClass&0xFF); // low byte

	}

	uint8 *rr;

	uint8* pos=ret+12+questionNameLength;

	if (answerRR)

	{

		rr=answerRR->build();

		uint16 len=answerRR->getLength();

		memcpy(pos,rr,len);

		pos+=len;

		delete rr;

	}

	if (authorityRR)

	{

		rr=authorityRR->build();

		uint16 len=authorityRR->getLength();

		memcpy(pos,rr,len);

		pos+=len;

		delete rr;

	}

	if (additionalRR)

	{

		rr=additionalRR->build();

		uint16 len=additionalRR->getLength();

		memcpy(pos,rr,len);

		delete rr;

	}

	return ret;

}







/*

                        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3

    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   |         NAME_TRN_ID           |0|  0x0  |0|0|1|0|0 0|B|  0x0  |

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   |          0x0001               |           0x0000              |

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   |          0x0000               |           0x0000              |

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   |                                                               |

   /                         QUESTION_NAME                         /

   /                                                               /

   |                                                               |

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   |           NB (0x0020)         |        IN (0x0001)            |

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/



NameQueryPacket::NameQueryPacket(const char* name, uint8 broadcast, uint16 id, uint8 status, bool groupFlag)

{

	name_trn_id=id;

	if( status )

	{

		nmFlags=(broadcast&1); qdcount=1;

		questionType=0x21; questionClass=1;

	}

	else

	{

		nmFlags=0x10+(broadcast&1); qdcount=1;

		questionType=0x20; questionClass=1;

	}

//	isGroup=groupFlag;

	questionName=NBName(name, groupFlag);

	questionNameLength=strlen(questionName)+1;

}



char *NameQueryPacket::getQueryNBName()

{

	if (!questionName) return 0;

	char *ret=new char[strlen(questionName)+1];

	strcpy(ret,questionName);

	return ret;

}

/*

void NameQueryPacket::setQueryNBName(const char *n, bool groupFlag)

{

	if (questionName) delete questionName;

	isGroup=groupFlag;

	questionName=new char[strlen(n)+1];

	questionNameLength=strlen(n)+1;

	strcpy(questionName,n);

}

*/

NameConflictDemand::NameConflictDemand(const char* name, uint16 id)

{

	name_trn_id=id; opcode=0x15; nmFlags=0x58; rcode=0x7;

	arcount=1;

	char *n=NBName(name);

	uint8* data=new uint8[6];

	for (int i=0; i<6; i++) data[i]=0;

	answerRR=new ResourceRecord(n,0x20,1,0, data,6);

	delete data;

	delete n;

}



#endif
#pragma code_seg()
#pragma data_seg()
#pragma bss_seg()
#pragma const_seg()

